#include "database/db_connection.hpp"
#include "common/config.hpp"
#include <iostream>


std::unique_ptr<DBConnection> DBConnection::m_instance = nullptr;

DBConnection::DBConnection() : m_connection(nullptr) {}

DBConnection* DBConnection::getInstance() {
    if (m_instance == nullptr) {
        m_instance = std::unique_ptr<DBConnection>(new DBConnection());
    }
    return m_instance.get();
}

bool DBConnection::connect() {
    m_connection = mysql_init(nullptr);
    if (m_connection == nullptr) {
        std::cerr << "MYSQL init failed" << std::endl;
        return false;
    }

    if (mysql_real_connect(m_connection, Config::DB_HOST.c_str(), 
                           Config::DB_USER.c_str(),
                           Config::DB_PASSWORD.c_str(),
                           Config::DB_NAME.c_str(),
                           0, nullptr, 0) ==  nullptr) {
        std::cerr << "MYSQL connect failed: " << mysql_error(m_connection) << std::endl;
        mysql_close(m_connection);
        m_connection = nullptr;
        return false;
    }

    mysql_set_character_set(m_connection, "utf8mb4");
    return true;
}

void DBConnection::disconnect() {
    if (m_connection) {
        mysql_close(m_connection);
        m_connection = nullptr;
    }
}


bool  DBConnection::execute(const std::string& query) {
    if (!m_connection) return false;

    if (mysql_query(m_connection, query.c_str()) != 0) {
        std::cerr << "Query failed:" << mysql_error(m_connection) << std::endl;
        return false;
    }
    return true;
}

MYSQL_RES* DBConnection::query(const std::string& sql) {
    if (!m_connection) return nullptr;

    if (mysql_query(m_connection, sql.c_str()) != 0) {
        std::cerr << "Query failed: " << mysql_error(m_connection) << std::endl;
        return nullptr;
    }
    return mysql_store_result(m_connection);
}

std::string DBConnection::escapeString(const std::string& str) {
    if (!m_connection) return str;

    char* escaped = new char[str.length() * 2 + 1];
    mysql_real_escape_string(m_connection, escaped, str.c_str(), str.length());
    std::string result(escaped);
    delete[] escaped;
    return result;
}

DBConnection::~DBConnection() {
    disconnect();
} 
